目標先講清楚:
把 Day 2 的即時語音助理升級為「能看圖、會看鏡頭」的 Vision Agent。
Input:語音/文字/圖片/視訊;Output:文字/語音。
仍然要能即時互動(real-time)。
維持原本語音管線(Deepgram STT → GPT → Cartesia TTS),再加兩件事:
整合對話生命週期:在使用者說完一句話(turn completed)時,自動把當下鏡頭畫面附加到該輪訊息,讓 LLM 能「同時看與聽」。
class Assistant(Agent):
def __init__(self) -> None:
super().__init__(instructions="You are a helpful voice AI assistant.")
Agent
async def entrypoint(ctx: agents.JobContext):
session = AgentSession(...)
語音處理鏈路:
deepgram.STT
(Nova-3,多語)Azure OpenAI GPT-4.1-mini
cartesia.TTS
(Sonic-2)智能語音控制:
vad = ctx.proc.userdata["vad"] # 語音活動偵測
turn_detection = MultilingualModel() # 多語言轉場偵測
await session.start(
room=ctx.room,
agent=Assistant(),
room_input_options=RoomInputOptions(
noise_cancellation=noise_cancellation.BVC(),
),
)
cli.run_app(WorkerOptions(
entrypoint_fnc=entrypoint,
initialize_process_timeout=60,
prewarm_fnc=prewarm
))
prewarm
預熱關鍵元件,加速啟動room=ctx.room
是一個 rtc.Room
,由 JobContext.connect()
連上 LiveKit 伺服器,負責完整 WebRTC 連線與媒體傳輸。LiveKit agents 在底層提供了自動對話循環,讓互動自然順暢。
在不動既有語音管線的前提下,透過擴充 Agent 行為加入圖片與視訊:
(Livekit提供以下3種的固定function,去達成)
on_enter
:註冊圖片資料流(byte stream handler)async def on_enter(self):
room = get_job_context().room
# 接收前端上傳的圖片("images" 通道)
def image_received_handler(reader, participant_identity):
task = asyncio.create_task(
self._image_received(reader, participant_identity)
)
self._tasks.append(task)
task.add_done_callback(lambda t: self._tasks.remove(t))
# 前端傳送示例:
# await room.localParticipant.publishData(uint8Array, "images")
room.register_byte_stream_handler("images", image_received_handler)
重點
on_enter
是 固定生命週期方法:Agent 進房時自動觸發# 當有新視訊軌道被訂閱時觸發
@room.on("track_subscribed")
def on_track_subscribed(track: rtc.Track, publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
if track.kind == rtc.TrackKind.KIND_VIDEO:
self._create_video_stream(track)
重點
_create_video_stream(track)
內部持續讀取畫面,緩存到 self._latest_frame
async def on_user_turn_completed(self, turn_ctx: ChatContext, new_message: dict) -> None:
# 如果有最新視訊幀,把它加到使用者該輪訊息內容中
if self._latest_frame:
if isinstance(new_message.content, list):
new_message.content.append(ImageContent(image=self._latest_frame))
else:
new_message.content = [new_message.content, ImageContent(image=self._latest_frame)]
self._latest_frame = None
效果
保持 Day 2 的即時語音體驗,新增:
互動從「會聽、會說」升級為 「會聽、會說、也會看」
Default(4/5)—— 將 Agent 邏輯替換為 LangGraph,把多步驟流程(工具呼叫、記憶、檢索等)圖形化與模組化,便於擴充與維運。